<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Support functions for theme rlmaster
 *
 * @package   theme-rlmaster
 * @copyright 2011 Remote Learner  http://www.remote-learner.net/
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

require_once(dirname(__FILE__).'/admin_settings.php');
require_once(dirname(__FILE__).'/defaults.php');

if (! function_exists('rlmaster_process_css')) {

    /**
     * Makes changes to the CSS
     *
     * @param string       $css   The css to be processed
     * @param theme_config $theme The theme containing the settings
     * @return string
     * @uses $OUTPUT
     */
    function rlmaster_process_css($css, $theme) {
        global $OUTPUT;

        $tokens = array(
            // sizes
            'bannerheight'            => THEME_RLMASTER_DEFAULT_BANNER_HEIGHT,
            'blockcorner'             => THEME_RLMASTER_DEFAULT_BLOCK_CORNER,
            'blockspace'              => THEME_RLMASTER_DEFAULT_BLOCK_SPACE,
            'fixedwidth'              => THEME_RLMASTER_DEFAULT_LAYOUT_FIXED,
            'fluidwidth'              => THEME_RLMASTER_DEFAULT_LAYOUT_FLUID,
            'headercorner'            => THEME_RLMASTER_DEFAULT_HEADER_CORNER,
            'headerheight'            => THEME_RLMASTER_DEFAULT_HEADER_HEIGHT,
            'headingheight'           => THEME_RLMASTER_DEFAULT_HEADING_HEIGHT,
            'logintop'                => THEME_RLMASTER_DEFAULT_LOGIN_TOP,
            'regionwidth'             => THEME_RLMASTER_DEFAULT_COL_WIDTH,
            // others
            'blockcontrol'     => THEME_RLMASTER_DEFAULT_BLOCK_CONTROL,
            'columns'          => THEME_RLMASTER_DEFAULT_COL_NUM,
            'col1align'        => 'left',
            'col2align'        => 'right',
            'customcss'        => '',
            'headingbar'       => 'block',
            'layouttype'       => THEME_RLMASTER_DEFAULT_LAYOUT_TYPE,
            'weekhighlight'    => THEME_RLMASTER_DEFAULT_WEEK_HIGHLIGHT,
            // images
            'background'              => THEME_RLMASTER_DEFAULT_IMG_BACKGROUND,
            'banner'                  => THEME_RLMASTER_DEFAULT_IMG_BANNER,
            'blockheadback'           => THEME_RLMASTER_DEFAULT_IMG_BLOCKHEADBACK,
            'custommenuback'          => THEME_RLMASTER_DEFAULT_IMG_CUSTOMMENUBACK,
            'favicon'                 => THEME_RLMASTER_DEFAULT_IMG_FAVICON,
            'footerback'              => THEME_RLMASTER_DEFAULT_IMG_FOOTERBACK,
            'headerback'              => THEME_RLMASTER_DEFAULT_IMG_HEADERBACK,
            'headerleft'              => THEME_RLMASTER_DEFAULT_IMG_HEADERLEFT,
            'headermenuback'          => THEME_RLMASTER_DEFAULT_IMG_HEADERMENUBACK,
            'headerright'             => THEME_RLMASTER_DEFAULT_IMG_HEADERRIGHT,
            'headingback'             => THEME_RLMASTER_DEFAULT_IMG_HEADINGBACK,
            // Rein.js Widget colors.
            'reindefaultlight' => THEME_RLMASTER_DEFAULT_COLOR_REIN_DEFAULT_LIGHT,
            'reindefaultmedium' => THEME_RLMASTER_DEFAULT_COLOR_REIN_DEFAULT_MEDIUM,
            'reindefaultdark' => THEME_RLMASTER_DEFAULT_COLOR_REIN_DEFAULT_DARK,
            'reinactivelight' => THEME_RLMASTER_DEFAULT_COLOR_REIN_ACTIVE_LIGHT,
            'reinactivemedium' => THEME_RLMASTER_DEFAULT_COLOR_REIN_ACTIVE_MEDIUM,
            'reinactivedark' => THEME_RLMASTER_DEFAULT_COLOR_REIN_ACTIVE_DARK
        );

        // colors
        foreach (rlmaster_admin_setting_colorarray::$sections as $k => $v) {
            foreach ($v as $value) {
                $name = $value;
                $constant = 'THEME_RLMASTER_DEFAULT_COLOR_'.strtoupper($name);

                if (defined($constant)) {
                    $tokens[$name] = constant($constant);
                } else {
                    $tokens[$name] = '#000000';
                }
            }
        }

        // Initialize the default images
        $prefix = 'THEME_RLMASTER_DEFAULT_IMG_';
        foreach (rlmaster_admin_setting_controls::$images as $image) {
            $tokens[$image] = '';
        }

        $tokens = rlmaster_check_settings($theme, $tokens);
        $tokens = rlmaster_create_generated_tokens($tokens);
        // Before updating css, format any default images properly for css
        $tokens = rlmaster_rewrite_image_urls($tokens);

        $css = rlmaster_swap_settings($css, $tokens);

        // Return the CSS
        return $css;
    }

    /**
     * Check to see if the default values have been overriden
     *
     * @param string $theme  The theme which possibly contains configured values
     * @param array  $tokens The tokens to be checked for overriden values
     * @return array The updated token list
     */
    function rlmaster_check_settings($theme, $tokens) {
        foreach ($tokens as $token => $default) {
            if (isset($theme->settings->$token) && ($theme->settings->$token !== '')) {
                $tokens[$token] = $theme->settings->$token;
            }
        }

        return $tokens;
    }

    /**
     * Verify that database value is not null or empty string.
     * If database value is null or empty string, set to default.
     *
     * @param string $themename The theme for which to verify the sane value
     * @param string $token The setting name (in tokens array and database)
     * @param string $default Default setting to use if database value is falsy
     */
    function rlmaster_check_not_null($themename, $token, $default) {

        // Get current database value for setting in question.
        $currentval = get_config($themename, $token);

        // If current db value is empty string or null, set it to default value
        if (($currentval == '') || ($currentval == null)) {
            set_config($token, $default, $themename);
        }
    }

    /**
     * Verify that database value is a sane value for the setting in question
     * (used if updates to the theme have removed prior select options)
     *
     * @param string $themename The theme for which to verify the sane value
     * @param string $token The setting name (in tokens array and database)
     * @param array $choices Array of select options for the setting in question
     */
    function rlmaster_set_sane_value($themename, $token, $choices) {

        // Get current database value for setting in question.
        $currentval = get_config($themename, $token);

        // Remove keys from array
        $indexedchoices = array_values($choices);

        // Boolean: Is the value in database in the array of valid options?
        $dbvalissane = in_array($currentval, $indexedchoices);

        // If current database value is not one of the select options, set database value to default
        if (!$dbvalissane) {
            $defaults = rlmaster_create_defaults();// Get theme defaults.
            set_config($token, $defaults[$token], $themename);
        }
    }

    /**
     * Check to see if the default image settings have been loaded
     *
     * @param object $theme The theme containing the settings
     * @param array  $defaults  Array of defaults from defaults.php
     * @return array The updated list of defaults
     */
    function rlmaster_check_default_images($theme, $defaults = array()) {
        global $CFG, $USER;

        if (isset($theme->name)) {
            $component = 'theme_'.$theme->name;
        } else {
            // Theme name is not yet set during install.
            $component = 'theme_rlmaster';
        }

        // Get defaults if they were not passed
        if (empty($defaults)) {
            $defaults = rlmaster_create_defaults();
        }
        $images_loaded = get_config($component, 'defaultimagesloaded');
        $theme_changed = rlmaster_detect_theme_changes($theme, $defaults);

        // If theme has not been changed and default images are not yet loaded, load them here
        if (!$images_loaded && !$theme_changed) {
            // Set a valid user id
            $currentuserid = $USER->id;
            $siteadmins = explode(',', $CFG->siteadmins);
            $USER->id = $siteadmins[0];
            // Load default images
            $defaults = rlmaster_load_default_images($component, $defaults);
            // Reset userid
            $USER->id = $currentuserid;
            set_config('defaultimagesloaded', true, $component);
        }

        return $defaults;
    }

    /**
     * Swap settings
     *
     * @param string $css    The css to modify
     * @param string $tokens The tokens to be replaced and the default values
     * @return string The modified css
     */
    function rlmaster_swap_settings($css, $tokens) {

        foreach ($tokens as $token => $replacement) {
            $tag = '[[setting:'.$token.']]';
            $css = str_replace($tag, $replacement, $css);
        }
        return $css;
    }

    /**
     * Clear out the theme's side cache.
     *
     * This method deletes the physical directory that is used to cache these theme
     * files used for serving.
     * @param   string  $theme  Theme name
     */
    function rlmaster_reset_theme_cache($theme) {
        global $CFG;
        require_once("$CFG->libdir/filelib.php");

        $next = time();
        if (isset($CFG->themerev) and $next <= $CFG->themerev and $CFG->themerev - $next < 60*60) {
            // This resolves problems when reset is requested repeatedly within 1s,
            // the < 1h condition prevents accidental switching to future dates
            // because we might not recover from it.
            $next = $CFG->themerev+1;
        }

        set_config('themerev', $next); // time is unique even when you reset/switch database
        fulldelete("$CFG->cachedir/theme/$theme");
    }

    /**
     * Create the tokens that depend on other token values.
     *
     * @param array $tokens    The tokens to be checked for overriden values
     * @return array The updated token list
     * @uses $CFG
     * @uses $OUTPUT
     * @uses $PAGE
     */
    function rlmaster_create_generated_tokens($tokens) {
        global $CFG, $OUTPUT, $PAGE;

        // Format header height for usage.
        $tokens['headerheight'] = (intval($tokens['headerheight'])) .'px';
        $tokens['regionwidthdouble'] = (intval($tokens['regionwidth']) * 2) .'px';
        $tokens['headertitletoppad'] = (intval(intval($tokens['headerheight'] - 45) / 2)) .'px';

        // Loads blocks if they haven't been loaded yet.
        $PAGE->blocks->load_blocks();

        // Flexible layout settings
        $has2col = ($tokens['columns'] == 2) || (! $PAGE->blocks->region_has_content('side-post', $OUTPUT));
        $noleft = ($tokens['col2align'] != 'left') || $has2col;
        $noleft = $noleft && ($tokens['col1align'] != 'left');

        $tokens['leftcolpad'] = $tokens['regionwidth'];
        $tokens['rightcolpad'] = $tokens['regionwidthdouble'];
        $tokens['col1leftpad']  = $tokens['regionwidth'];
        $tokens['col2leftpad'] = 0;

        if ($noleft) {
            $tokens['leftcolpad'] = 0;
        }
        // Special case if both columns aligned to the same side

        if ($tokens['col1align'] == 'right') {
            $tokens['col1leftpad'] = 0;

            if ($has2col) {
                $tokens['rightcolpad'] = $tokens['regionwidth'];
            }
        }

        if ($tokens['col2align'] == 'left') {
            $tokens['col2leftpad'] = $tokens['regionwidth'];
        }

        if ((! $has2col) && ($tokens['col1align'] == $tokens['col2align'])) {
            $tokens['col2leftpad'] = $tokens['regionwidth'];

            if ($tokens['col1align'] == 'left') {
                $tokens['leftcolpad'] = $tokens['regionwidthdouble'];
                $tokens['col1leftpad'] = 0;
            }
        }

        if ($tokens['blockcontrol'] == 'bottom') {
            $tokens['blockcontroltop'] = ($tokens['headingheight'] - 11) .'px';
        } else if ($tokens['blockcontrol'] == 'middle') {
            $tokens['blockcontroltop'] = ($tokens['headingheight'] - 11) / 2 .'px';
        } else {
            $tokens['blockcontroltop'] = '0px';
        }

        if ($tokens['layouttype'] == 'fixed') {
            $tokens['pagewidth'] = $tokens['fixedwidth'];
        } else {
            $tokens['pagewidth'] = $tokens['fluidwidth'];
        }

        if ($tokens['weekhighlight'] == 'ends') {
            $tokens['current_content_back'] = $tokens['main_back'];
        } else {
            $tokens['current_content_back'] = $tokens['current_back'];
        }

        return $tokens;
    }

    /**
     * Set up an array with all defaults set for the reset function
     *
     * @return  array   $tokens An array mapping fields to their default values for this theme
     */
    function rlmaster_create_defaults() {
        $tokens = array(
            'customcss' => '',
            'headcustomhtml' => '',
            'headercustomhtml' => '',
            'footercustomhtml' => '',
            'layouttype' => '',
            'fluidwidth' => '',
            'fixedwidth' => '',
            'columns' => THEME_RLMASTER_DEFAULT_COL_NUM,
            'col1align' => 'left',
            'col2align' => 'right',
            'regionwidth' => THEME_RLMASTER_DEFAULT_COL_WIDTH,
            'headerheight' => THEME_RLMASTER_DEFAULT_HEADER_HEIGHT,
            'bannerheight' => THEME_RLMASTER_DEFAULT_BANNER_HEIGHT,
            'custommenu' => THEME_RLMASTER_DEFAULT_CUSTOM_MENU,
            'logintop' => THEME_RLMASTER_DEFAULT_LOGIN_TOP,
            'headercorner' => THEME_RLMASTER_DEFAULT_HEADER_CORNER,
            'headingheight' => THEME_RLMASTER_DEFAULT_HEADING_HEIGHT,
            'blockcorner' => THEME_RLMASTER_DEFAULT_BLOCK_CORNER,
            'blockcontrol' => THEME_RLMASTER_DEFAULT_BLOCK_CONTROL,
            'blockspace' => THEME_RLMASTER_DEFAULT_BLOCK_SPACE,
            'tagline' => '',
            'headingbar' => 'block',
            'weekhighlight' => THEME_RLMASTER_DEFAULT_WEEK_HIGHLIGHT,
            // images
            'background' => THEME_RLMASTER_DEFAULT_IMG_BACKGROUND,
            'banner' => THEME_RLMASTER_DEFAULT_IMG_BANNER,
            'blockheadback' => THEME_RLMASTER_DEFAULT_IMG_BLOCKHEADBACK,
            'custommenuback' => THEME_RLMASTER_DEFAULT_IMG_CUSTOMMENUBACK,
            'favicon' => THEME_RLMASTER_DEFAULT_IMG_FAVICON,
            'footerback' => THEME_RLMASTER_DEFAULT_IMG_FOOTERBACK,
            'headerback' => THEME_RLMASTER_DEFAULT_IMG_HEADERBACK,
            'headerleft' => THEME_RLMASTER_DEFAULT_IMG_HEADERLEFT,
            'headermenuback' => THEME_RLMASTER_DEFAULT_IMG_HEADERMENUBACK,
            'headerright' => THEME_RLMASTER_DEFAULT_IMG_HEADERRIGHT,
            'headingback' => THEME_RLMASTER_DEFAULT_IMG_HEADINGBACK,
            // Rein.js Widget colors.
            'reindefaultlight' => THEME_RLMASTER_DEFAULT_COLOR_REIN_DEFAULT_LIGHT,
            'reindefaultmedium' => THEME_RLMASTER_DEFAULT_COLOR_REIN_DEFAULT_MEDIUM,
            'reindefaultdark' => THEME_RLMASTER_DEFAULT_COLOR_REIN_DEFAULT_DARK,
            'reinactivelight' => THEME_RLMASTER_DEFAULT_COLOR_REIN_ACTIVE_LIGHT,
            'reinactivemedium' => THEME_RLMASTER_DEFAULT_COLOR_REIN_ACTIVE_MEDIUM,
            'reinactivedark' => THEME_RLMASTER_DEFAULT_COLOR_REIN_ACTIVE_DARK
        );

        // Set default colors
        $prefix = 'THEME_RLMASTER_DEFAULT_COLOR_';

        foreach (rlmaster_admin_setting_colorarray::$sections as $k => $v) {
            foreach ($v as $value) {
                $name = $value;
                $constant = $prefix.strtoupper($name);

                if (defined($constant)) {
                    $tokens[$name] = constant($constant);
                } else {
                    $tokens[$name] = '#000000';
                }
            }
        }

        // Set default images
        $prefix = 'THEME_RLMASTER_DEFAULT_IMG_';
        foreach (rlmaster_admin_setting_controls::$images as $image) {
            $constant = $prefix.strtoupper($image);
            if (defined($constant)) {
                $tokens[$image] = constant($constant);
            } else {
                $tokens[$image] = '';
            }
        }

        return $tokens;
    }

    /**
     * Load default images
     *
     * @param string $component Plugin name
     * @param array  $defaults  Array of defaults from defaults.php
     * @return array The updated list of defaults
     */
    function rlmaster_load_default_images($component, $defaults) {
        global $CFG, $USER;

        // Set File area defaults
        $basefilearea = 'files';
        $basefilepath = '/';
        $basecontextid = SITEID;
        $pluginroot = '/pluginfile.php/';

        $themepixpath = '/'.preg_replace('/_/', '/', $component, 1).'/pix/';

        // Reset theme images
        // Remove all images stored for this theme
        $fs = get_file_storage();

        // Get initial defaults.
        $initialdefaults = rlmaster_create_defaults();

        // Insert any default images
        $name = $component.'/control_heading';
        $title = get_string('themecontrols', $component);
        foreach (rlmaster_admin_setting_controls::$images as $image) {
            // Remove any existing defaults
            set_config($image, '', $component);

            $url = $initialdefaults[$image];
            if (($url != '')) {
                $filepath = $CFG->dirroot.$themepixpath.$url;
                $filename = basename($url);
                // Check if file exists
                if (!file_exists($filepath)) {
                    $errors[] = get_string('missingfile', $component, $filename);
                    continue;
                }

                $itemid = file_get_unused_draft_itemid();
                $filearea = $image.'_'.$basefilearea;
                $source = $filename;

                // Author needs to be default site admin
                $admin = get_admin();
                $author = fullname($admin);
                $userid = $admin->id;
                if (isset($CFG->sitedefaultlicense)) {
                    $license = $CFG->sitedefaultlicense;
                } else {
                    $license = null;
                }

                // Each file needs to be treated as if it was added via the file manager,
                // thus rendering it editable in the images tab

                // Create draft area file first
                $usercontext = context_user::instance($USER->id);
                $draftfileinfo = array(
                    'contextid' => $usercontext->id,
                    'component' => 'user',
                    'filearea'  => 'draft',
                    'itemid'    => $itemid,
                    'filepath'  => $basefilepath,
                    'filename'  => $filename,
                    'source'    => $source,
                    'author'    => $author,
                    'userid'    => $userid,
                    'license'   => $license
                );

                // Save draft file to database
                $saveresult = $fs->create_file_from_pathname($draftfileinfo, $filepath);

                // Create theme file to be saved in database
                $fileinfo = array(
                    'contextid' => $basecontextid,
                    'component' => $component,
                    'filearea'  => $filearea,
                    'itemid'    => $itemid,
                    'filepath'  => $basefilepath,
                    'filename'  => $filename,
                    'source'    => $source,
                    'author'    => $author,
                    'userid'    => $userid,
                    'license'   => $license
                );

                // Filepath should be filearea / itemid / filename
                $path = $filearea.'/'.$itemid.'/'.$filename;

                // check if the file exists in the file cache
                if ($file = $fs->get_file_by_hash(sha1($path))) {
                    $file->delete();
                }

                // Clear out previous theme files for this element
                $fs->delete_area_files($basecontextid, $component, $filearea);

                // Save file to database
                $saveresult = $fs->create_file_from_pathname($fileinfo, $filepath);

                // Update the defaults array with the proper filepath for this image
                $value = $pluginroot.$basecontextid.'/'.$component.'/'.$path;
                $defaults[$image] = $value;

                // Store change
                set_config($image, $value, $component);
            }
        }
        return $defaults;
    }

    /**
     * Detect any changes to the theme
     *
     * @param   theme_config $theme The theme containing the settings
     * @param   array   $defaults Array of defaults
     * @return  boolean true if theme has changed, false otherwise
     */
    function rlmaster_detect_theme_changes($theme, $defaults) {
        // Update the defaults array with any stored settings
        $updated_config = rlmaster_check_settings($theme, $defaults);

        // Check for config changes
        $array_diff = array_diff_assoc($defaults, $updated_config);
        if (empty($array_diff)) {
            $return = false;
        } else {
            $return = true;
        }

        return $return;
    }

    /**
     * Re-write image path if required
     *
     * @param array $tokens Default settings
     * @return array $return Settings updated with rewritten image url for css
     */
    function rlmaster_rewrite_image_urls($tokens) {
        global $CFG;

        foreach ($tokens as $token => $value) {
            // If this is an image, make sure it is in the proper format for the css
            if (in_array($token, rlmaster_admin_setting_controls::$images) && !empty($value)) {
                // Only rewrite if the path of the image does not begin with "url("
                $start = "url(";
                if (!strstr($value, $start)) {
                    // Add a slash at the beginning if it is missing
                    $slash = '/';
                    if (!strpos($value, '/', 0) == 0) {
                        $slash = '';
                    }
                    // Add the wwwroot and then enclose the url with url("")
                    $value = $start.'"'.$CFG->wwwroot.$slash.$value.'")';
                }
                $tokens[$token] = $value;
            }
        }
        return $tokens;
    }
}

/**
 * Serves images files (mostly).
 *
 * If this theme is copied and renamed, you will need to change this function's name.
 *
 * @param object $course        The course object
 * @param object $cm            The course module object
 * @param object $context       The context object
 * @param string $filearea      The filearea name
 * @param array  $args          The array of other arguments
 * @param bool   $forcedownload Whether to force the image to be downloaded (not used)
 * @return bool false if file not found, does not return if found - just send the file
 */
function theme_rlmaster_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {

    $component = substr(__FUNCTION__, 0, strrpos(__FUNCTION__, '_'));

    $fs   = get_file_storage();
    $path = "/{$context->id}/$component/$filearea/". implode('/', $args);
    $file = $fs->get_file_by_hash(sha1($path));

    if (! is_object($file) || $file->is_directory()) {
        send_file_not_found();
    }

    session_get_instance()->write_close(); // unlock session during fileserving
    send_stored_file($file, 60*60, 0, false);
}
